`timescale 1ns/100ps

`include "sim_glb.sv"

module tc;

localparam          INFO_BW                 = 8;
localparam          RESP_BW                 = 3;
localparam          INFO_INPUT_HOLD         = 1'b1;     // set it to 1'b0 for area saving if src_info/src_nfr is REG and stable during src_req==1'b1
localparam          RESP_INPUT_HOLD         = 1'b0;     // set it to 1'b0 for area saving if dst_resp is REG and stable until next dst_ack==1'b1
localparam          SYNC_NUM_D2S            = 3;
localparam          SYNC_NUM_S2D            = 3;
localparam          INFO_INC                = 5;
localparam          RESP_INC                = 3;

reg                                         rst_src_n;
reg                                         clk_src;

reg                                         src_req;    // keep src_req 1'b1 until src_ack==1'b1
reg                 [INFO_BW-1:0]           src_info;   // forward information
reg                                         src_nfr;    // 1'b1: need for response; 1'b0 not need for response
wire                                        src_ack;
wire                [RESP_BW-1:0]           src_resp;   // backward response

reg                                         rst_dst_n;
reg                                         clk_dst;

wire                                        dst_req;
wire                [INFO_BW-1:0]           dst_info;
wire                                        dst_nfr;    // 1'b1: need for response; 1'b0 not need for response
reg                                         dst_ack;
reg                 [RESP_BW-1:0]           dst_resp;


initial begin:CRG
    rst_src_n=1'b0;
    clk_src=1'b0;
    rst_dst_n=1'b0;
    clk_dst=1'b0;

    fork
        rst_src_n=#100.5 1'b1;
        rst_dst_n=#100.5 1'b1;

        forever clk_src=#4 ~clk_src;
        forever clk_dst=#5 ~clk_dst;
    join
end

RGRS_MNG    rgrs;
initial begin:REGRESS
    rgrs = new("tc_sync_req", 1);

    rgrs.wait_chks_done(100_000_000);
end

initial begin:GEN_REQ
    reg [INFO_BW-1:0]   gen_info;
    reg [RESP_BW-1:0]   chk_resp;
    integer             gap;

    src_req  = 0;
    src_info = 0;
    src_nfr  = 0;
    gen_info = 0;
    chk_resp = 0;

    @(posedge rst_src_n);
    @(posedge clk_src);

    repeat (20_000) begin
        gap = $urandom_range(0, 10);
        repeat(gap) begin
            @(posedge clk_src);
        end
        src_req  = `U_DLY 1'b1;
        src_info = `U_DLY gen_info;
        src_nfr  = `U_DLY $urandom_range(0, 1);
        @(posedge clk_src);

        while(src_ack==1'b0) begin
            @(posedge clk_src);
        end

        chk_resp = src_info + RESP_INC;
        gen_info = gen_info + INFO_INC;
        if ((src_nfr==1'b1) && (src_resp!=chk_resp)) begin
            $error("src_resp %h is not expected %h", src_resp, chk_resp);
            $stop;
        end
        src_req  = `U_DLY 1'b0;
    end

    rgrs.one_chk_done("req is done.");
end

sync_req #(
        .INFO_BW                        (INFO_BW                        ),
        .RESP_BW                        (RESP_BW                        ),
        .INFO_INPUT_HOLD                (INFO_INPUT_HOLD                ),	// set it to 1'b0 for area saving if src_info/src_nfr is REG and stable during src_req==1'b1
        .RESP_INPUT_HOLD                (RESP_INPUT_HOLD                ),	// set it to 1'b0 for area saving if dst_resp is REG and stable until next dst_ack==1'b1
        .SYNC_NUM_D2S                   (SYNC_NUM_D2S                   ),
        .SYNC_NUM_S2D                   (SYNC_NUM_S2D                   )
) u_sync_req ( 
        .rst_src_n                      (rst_src_n                      ),
        .clk_src                        (clk_src                        ),

        .src_req                        (src_req                        ),	// keep src_req 1'b1 until src_ack
        .src_info                       (src_info                       ),	// forward information
        .src_nfr                        (src_nfr                        ),	// 1'b1: need for response; 1'b0 not need for response
        .src_ack                        (src_ack                        ),
        .src_resp                       (src_resp                       ),	// backward response

        .rst_dst_n                      (rst_dst_n                      ),
        .clk_dst                        (clk_dst                        ),

        .dst_req                        (dst_req                        ),
        .dst_info                       (dst_info                       ),
        .dst_nfr                        (dst_nfr                        ),	// 1'b1: need for response; 1'b0 not need for response
        .dst_ack                        (dst_ack                        ),
        .dst_resp                       (dst_resp                       )
);

initial begin:GEN_ACK
    reg     [INFO_BW-1:0]   chk_info;
    integer                 job_time;

    dst_ack  = 0;
    dst_resp = 0;
    chk_info = 0;

    @(posedge rst_dst_n);

    @(negedge clk_dst);
    forever begin
        while(dst_req==1'b0) begin
            @(negedge clk_dst);
        end

        if (dst_info!=chk_info) begin
            $error("dst_info %h is not expected %h", dst_info, chk_info);
            $stop;
        end

        job_time = $urandom_range(0, 10); 
        repeat(job_time) begin
            @(negedge clk_dst);
        end

        dst_ack  = 1;
        dst_resp = (dst_nfr==1'b1) ? (dst_info + RESP_INC) : 0;
        chk_info = dst_info + INFO_INC;
        @(negedge clk_dst);
        dst_ack  = 0;
    end
end

endmodule

